package com.flute.haflute.net;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.keepalive.KeepAliveFilter;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import org.apache.mina.filter.keepalive.KeepAliveRequestTimeoutHandler;

/**
 * 该类专为MINA通信框架的心跳机制使用<br>
 * 
 * MINA心跳的作用：维持长连接。原理：使用KeepAliveFilter来定期发送心跳消息<br>
 * 
 * 一般MINA Session超时为60s，所以为保持一个超过1分钟的连接(Session)可用，需要使用心跳机制，
 * 而设置ConnectionTimeOut超过1分钟是没有用的。<br>
 * 
 * 心跳的filter设置以后，不要设置IdleTime(acceptor.getSessionConfig().setIdleTime?)<br>
 * 
 * 默认的构造器是一个完备的实现。
 * 
 */
public class HafluteKeepAliveFilterInMina extends KeepAliveFilter {

	// in seconds should not larger than 59s
	private static final int INTERVAL = 30;

	// in seconds
	private static final int TIMEOUT = 10;

	public HafluteKeepAliveFilterInMina(KeepAliveMessageFactory messageFactory) {
		super(messageFactory, IdleStatus.BOTH_IDLE, new ExceptionHandler(),
				INTERVAL, TIMEOUT);
	}

	public HafluteKeepAliveFilterInMina() {
		super(new KeepAliveMessageFactoryImpl(), IdleStatus.BOTH_IDLE,
				new ExceptionHandler(), INTERVAL, TIMEOUT);
		this.setForwardEvent(false);
	}
}

class ExceptionHandler implements KeepAliveRequestTimeoutHandler {
	public void keepAliveRequestTimedOut(KeepAliveFilter filter,
			IoSession session) throws Exception {
		System.out.println("Connection lost, session will be closed");
		session.close(true);
	}
}

/**
 * 继承于KeepAliveMessageFactory，当心跳机制启动的时候，需要该工厂类来判断和定制心跳消息
 * 
 */
class KeepAliveMessageFactoryImpl implements KeepAliveMessageFactory {

	private static final byte int_req = -1;

	private static final byte int_rep = -2;

	private static final IoBuffer KAMSG_REQ = IoBuffer
			.wrap(new byte[] { int_req });

	private static final IoBuffer KAMSG_REP = IoBuffer
			.wrap(new byte[] { int_rep });

	public Object getRequest(IoSession session) {
		return KAMSG_REQ.duplicate();
	}

	public Object getResponse(IoSession session, Object request) {
		return KAMSG_REP.duplicate();
	}

	public boolean isRequest(IoSession session, Object message) {
		if (!(message instanceof IoBuffer))
			return false;
		IoBuffer realMessage = (IoBuffer) message;
		if (realMessage.limit() != 1)
			return false;

		boolean result = (realMessage.get() == int_req);
		realMessage.rewind();
		return result;
	}

	public boolean isResponse(IoSession session, Object message) {
		if (!(message instanceof IoBuffer))
			return false;
		IoBuffer realMessage = (IoBuffer) message;
		if (realMessage.limit() != 1)
			return false;

		boolean result = (realMessage.get() == int_rep);
		realMessage.rewind();
		return result;
	}
}